package hasthi.manager.gui;

import hasthi.actuators.ActionContext;
import hasthi.actuators.CreateServiceAction;
import hasthi.actuators.ManagementAction;
import hasthi.actuators.SystemActionsScheduler;
import hasthi.actuators.actions.ActionCallback;
import hasthi.actuators.actions.RestartAction;
import hasthi.actuators.actions.ShutDownAction;
import hasthi.common.HasthiException;
import hasthi.common.Utils;
import hasthi.common.constants.HasthiConstants;
import hasthi.common.constants.WSDMConstants;
import hasthi.config.ResourceProfile;
import hasthi.container.MessageContext;
import hasthi.container.SimpleMessageContext;
import hasthi.manager.ExecuteCommandDocument;
import hasthi.manager.ExecuteCommandResponseDocument;
import hasthi.manager.ManagerPingRequestDocument;
import hasthi.manager.ManagerPingResponseDocument;
import hasthi.manager.UserInterventionDocument;
import hasthi.manager.ExecuteCommandDocument.ExecuteCommand;
import hasthi.manager.ManagementRingDocument.ManagementRing;
import hasthi.metamodel.resource.Host;
import hasthi.metamodel.resource.ManagedResource;
import hasthi.metamodel.resource.ManagedResource.ResourceType;

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextArea;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.indiana.extreme.wsdm.ShutDownRequestDocument;
import edu.indiana.extreme.wsdm.ShutDownRequestDocument.ShutDownRequest;

public class ActionPanel extends JPanel implements ActionListener{
    private final UIContext uicontext;
    private static Log log = LogFactory.getLog(HasthiConstants.LOGGER_NAME);
    
    public static enum ResourceActions{Stop, Restart,Create};
    private boolean isActiveManagement;
    
    public ActionPanel(UIContext context) throws HasthiException {
        //super(new GridLayout(10,2,10,10));
        super();
        this.uicontext = context;
        
        JPanel panel =  new JPanel(new GridBagLayout());
        add(panel,BorderLayout.NORTH);
        
        ActionContext actionContext = context.getActionScheduler().getActionContext();
        ResourceProfile[] resourceProfiles = actionContext.getSystemConfig().getProfile().getResourceArray();
        
        ResourceProfileDecarator[] resourceList = new ResourceProfileDecarator[resourceProfiles.length];
        int i = 0;
        for(ResourceProfile resourceProfile:resourceProfiles){
            resourceList[i] = new ResourceProfileDecarator(resourceProfile);    
            i++;
        }

        
        panel.add(new Label("Service Name"),createConstraints(0, 0));
        final JComboBox petList = new JComboBox(resourceList);
        petList.addActionListener(this);
        panel.add(petList,createConstraints(1, 0));
        
        
        ManagedResource[] allresources = context.getExternalResourceModel().getAllResources();
        List<ManageResourceDecarator> allhosts = new ArrayList<ManageResourceDecarator>();
        final List<ManagedResource> activeHostList = new ArrayList<ManagedResource>();
        
        for(ManagedResource resource:allresources){
            if(ResourceType.Host.toString().equals(resource.getCategory())){
                allhosts.add(new ManageResourceDecarator(resource));  
                activeHostList.add(resource);
            }
        }
        
        panel.add(new Label("Host"),createConstraints(0, 1));
        final JComboBox hostList = new JComboBox(allhosts.toArray());
        
        hostList.addActionListener(this);
        panel.add(hostList,createConstraints(1, 1));
        
        JButton button = new JButton("Create Service");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ActionCallback callback = new ActionCallback() {
                    public void actionSucessful(ManagementAction action) {
                        JOptionPane.showMessageDialog(null, "Action Completed");
                    }
                    public void actionFailed(ManagementAction action, Throwable e) {
                        uicontext.getOutputConsole().writeToConsole(Utils.errorTraceAsStr(e));
                        e.printStackTrace();
                        JTextArea area = new JTextArea(Utils.errorTraceAsStr(e));
                        JOptionPane.showMessageDialog(null, area);
                    }
                };
                try {
                    ResourceProfileDecarator decarator = (ResourceProfileDecarator)petList.getSelectedItem();
                    final String serviceName = decarator.getResourceProfile().getName().toString();
                    log.info("Create Action "+ serviceName + " is triggered");
                    CreateServiceAction createServiceAction = new CreateServiceAction(serviceName,null);
                    createServiceAction.setHostAgents(activeHostList);
                    final SystemActionsScheduler actionScheduler = uicontext.getActionScheduler();
                    actionScheduler.invoke(createServiceAction,callback);
                    actionScheduler.planAndExecuate();
                } catch (HasthiException e1) {
                    callback.actionFailed(null, e1);
                }
            }
        });
        panel.add(button,createConstraints(1, 3));
        
        
        if(uicontext.getCoordinatorUrl()!= null){
            ManagerPingRequestDocument document = ManagerPingRequestDocument.Factory.newInstance();
            document.addNewManagerPingRequest();
            ManagerPingResponseDocument responseDocument = (ManagerPingResponseDocument)uicontext.getContainer().sendReceive(
                    new SimpleMessageContext(document,uicontext.getCoordinatorUrl(),HasthiConstants.MANAGER_PING_ACION));
            ManagementRing managementRing = responseDocument.getManagerPingResponse().getManagerContext().getManagementRing();
            if(managementRing != null){
                isActiveManagement = managementRing.getActiveManagement();
                final JButton managementStatusButton  = new JButton(isActiveManagement?"DisableManagement":"EnableManagement");
                managementStatusButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        try {
                            isActiveManagement = !isActiveManagement;
                            managementStatusButton.setText(isActiveManagement?"DisableManagement":"EnableManagement");
                            UserInterventionDocument document = UserInterventionDocument.Factory.newInstance();
                            document.addNewUserIntervention().setActiveManagement(isActiveManagement);
                            uicontext.getContainer().sendReceive(new SimpleMessageContext(document,
                                    uicontext.getCoordinatorUrl(),HasthiConstants.USER_INTERVENTION_ACTION));
                        } catch (HasthiException e1) {
                            uicontext.getOutputConsole().writeToConsole(Utils.errorTraceAsStr(e1));
                            e1.printStackTrace();
                            JTextArea area = new JTextArea(Utils.errorTraceAsStr(e1));
                            JOptionPane.showMessageDialog(null, area);
                        }
                    }
                });
                
                panel.add(new JLabel(""),createConstraints(0, 4));
                GridBagConstraints c = createConstraints(0, 5);
                c.gridwidth = 2;
                c.weighty = 1;
                
                panel.add(new JSeparator(JSeparator.HORIZONTAL),c);
                panel.add(new JLabel("Hasthi Management Status "),createConstraints(0, 6));
                panel.add(managementStatusButton,createConstraints(1, 6));
            }
        }
        
    }
    
    
    private GridBagConstraints createConstraints(int x,int y) {
        GridBagConstraints c = new GridBagConstraints();
        // natural height, maximum width
        c.fill = GridBagConstraints.HORIZONTAL;

        c.weightx = 0.5;
        c.weighty = 0.3;
        c.gridx = x;
        c.gridy = y;
        return c;
    }
    
    public void actionPerformed(ActionEvent e) {
    }
    
    
    public class ManageResourceDecarator{
        private ManagedResource managedResource;
        public ManageResourceDecarator(ManagedResource managedResource) {
            this.managedResource = managedResource;
        }
        public ManagedResource getManagedResource() {
            return managedResource;
        }
        @Override
        public String toString() {
            return managedResource.getQName().getLocalPart();
        }
        
    }
    
    public static void sendShutdownMessage(UIContext uicontext, String endpointUrl) throws HasthiException{
        ShutDownRequestDocument requestDocument = ShutDownRequestDocument.Factory.newInstance();
        ShutDownRequest shutDownRequest = requestDocument.addNewShutDownRequest();
        MessageContext message = new SimpleMessageContext(shutDownRequest, endpointUrl,
                WSDMConstants.ACTION_SHUTDOWN);
        uicontext.getContainer().sendReceive(message);
    }
    
    public static void runCommand(UIContext uicontext, String endpointUrl, String installDir,String command) throws HasthiException{
        ExecuteCommandDocument commandDocument = ExecuteCommandDocument.Factory
        .newInstance();
        ExecuteCommand executeCommand = commandDocument.addNewExecuteCommand();
        executeCommand.setWorkdir(installDir);
        executeCommand.setCmd(command);
        ExecuteCommandResponseDocument responseDocument = (ExecuteCommandResponseDocument)uicontext.getContainer().sendReceive(new SimpleMessageContext(commandDocument, endpointUrl, HasthiConstants.EXECUATE_COMMAND_ACTION));
        log.info("Stdout for command "+ command + " is "+responseDocument.getExecuteCommandResponse().getStdouterr());
    }
   
    
    public static void execuateActionOnResource(final UIContext uicontext,ActionPanel.ResourceActions action,ManagedResource resource){
        ActionCallback callback = new ActionCallback() {
            public void actionSucessful(ManagementAction action) {
                JOptionPane.showMessageDialog(null, "Action Completed");
            }
            public void actionFailed(ManagementAction action, Throwable e) {
                uicontext.getOutputConsole().writeToConsole(Utils.errorTraceAsStr(e));
                e.printStackTrace();
                JTextArea area = new JTextArea(Utils.errorTraceAsStr(e));
                JOptionPane.showMessageDialog(null, area);
            }
        };
        try {
            final SystemActionsScheduler actionScheduler = uicontext.getActionScheduler();
            switch(action){
                case Stop:
                    actionScheduler.invoke(new ShutDownAction(resource),callback);    
                    break;
                case Restart:
                    final List<ManagedResource> activeHostList = new ArrayList<ManagedResource>();
                    ManagedResource[] allresources = uicontext.getExternalResourceModel().getAllResources();
                    for(ManagedResource resourceObj:allresources){
                        if(ResourceType.Host.toString().equals(resourceObj.getCategory())){
                            activeHostList.add(resourceObj);
                        }
                    }
                    RestartAction restartAction = new RestartAction(resource);
                    restartAction.setHostAgents(activeHostList);
                    actionScheduler.invoke(restartAction,callback);
                    break; 
                    
            }
            actionScheduler.planAndExecuate();
            
        } catch (HasthiException e1) {
            callback.actionFailed(null, e1);
        }
    }
    
    public static void restartAllServices(final UIContext uicontext) throws HasthiException{
        int count = 0 ;
        ManagedResource[] allResources = uicontext.getExternalResourceModel().getAllResources();
        for(ManagedResource resource:allResources){
            if(ResourceType.Service.toString().equals(resource.getCategory())){
                execuateActionOnResource(uicontext, ResourceActions.Restart, resource);
                count++;
            }
        }
        JOptionPane.showMessageDialog(null, "Action Completed, "+count +" resources restarted");
    }
    
    public static void shutDownAllServices(final UIContext uicontext) throws HasthiException{
        int count = 0 ;
        ManagedResource[] allResources = uicontext.getExternalResourceModel().getAllResources();
        for(ManagedResource resource:allResources){
            if(ResourceType.Service.toString().equals(resource.getCategory())){
                execuateActionOnResource(uicontext, ResourceActions.Stop, resource);
                count++;
            }
        }
        JOptionPane.showMessageDialog(null, "Action Completed, "+count +" resources stopped");
    }
    
    public static void shutDownAllAppServices(final UIContext uicontext) throws HasthiException{
        int count = 0 ;
        ManagedResource[] allResources = uicontext.getExternalResourceModel().getAllResources(); 
        for(ManagedResource resource:allResources){
            if(ResourceType.TransientService.toString().equals(resource.getCategory())){
                execuateActionOnResource(uicontext, ResourceActions.Stop, resource);
            }
        }
        JOptionPane.showMessageDialog(null, "Action Completed, "+count +" resources stopped");
        
    }
    
    public class ResourceProfileDecarator{
        private ResourceProfile resourceProfile;
        public ResourceProfileDecarator(ResourceProfile resourceProfile) {
            this.resourceProfile = resourceProfile;
        }
        public ResourceProfile getResourceProfile() {
            return resourceProfile;
        }
        @Override
        public String toString() {
            return resourceProfile.getName().getLocalPart();
        }
        
    }
    
   
    
}
